/******************************************************************************
** 公司名称：天津柯迪斯科技有限公司
** 版权信息：
** 文件名称： App_Protocol_ANANDA_CAN.c
** 模块名称： 安乃达CAN协议处理模块
** 版 本 号： V1.0
** 作    者： 蒲磊
**
** 修改记录： 版本     修改人      时间         修改内容
**           V1.1    蒲磊       2023.01.03    发送挡位值，按照实际发送，不再判断挡位范围
**           V1.2    蒲磊       2023.02.04    修改了骑行时间数据类型错误的Bug，uint8_t 改为 uint16_t
**           V1.3    蒲磊       2023.02.07    获取电量函数，去掉了读取控制器电量等级的过程。改为如果读不到BMS的SOC，直接返回-1
**           V1.4    蒲磊       2023.02.16    控制器骑行时间帧（0x18FE07EF），改为请求方式（控制器更改了，原来是广播模式，现在改为请求模式）。1S请求一次
**           V1.5    蒲磊       2023.04.07    删掉了旧的设置限速的函数，增加了设置轮径的函数
                                              修改了开机上电和退出设置时，重新设置轮径函数（如需要设置轮周长，需自行修改）
**           V1.6    蒲磊       2023.04.10    修改了获取错误代码的函数。屏蔽了协议中没有的代码
******************************************************************************/

/******************************************************************************
* 头文件
******************************************************************************/
#include <string.h>
#include "Config.h"
#include "App_Protocol.h"
#include "App_MainTask.h"
#include "App_Parameter.h"
#include "multi_cyc_fifo.h"
#include "bsp.h"
/******************************************************************************
* 本文件宏定义 ('#define')
******************************************************************************/

/******************************************************************************
* 本文件类型定义 ('typedef')
******************************************************************************/

/******************************************************************************
* 本文件静态函数声明 ('static')
******************************************************************************/
static void vCAN_Receive_MCU_Message(strANANDA_CAN *pCanMsg,strBikeInfo *pBikeInfo);
static void vCAN_Receive_BMS_Message(strANANDA_CAN *pCanMsg,strBikeInfo *pBikeInfo);
static void vCan_Send_DisplayMessage(uint32_t PGN,strBikeInfo   *pBikeInfo);
static void vPROTOCOL_Factory_Response(uint32_t Cmd,uint16_t Data);
/******************************************************************************
* 全局变量定义
******************************************************************************/
strBikeInfo     gxBikeInfo = {0};         /*车辆数据*/
uint8_t     gucDisplay_Hard_Ver_1[] = {"        "};
uint8_t     gucDisplay_Hard_Ver_2[] = {"  V1.0.1"};
uint8_t     gucDisplay_Soft_Ver_1[] = {"        "};
uint8_t     gucDisplay_Soft_Ver_2[] = {"  V1.0.1"};
uint8_t     gucDisplay_SN_1[]       = {"        "};
uint8_t     gucDisplay_SN_2[]       = {"        "};
uint8_t     gucDisplay_SN_3[]       = {"00000000"};
static uint32_t gulCommunicationCnt = 0;
/*****************************************************************************
* 函数实现 - global ('extern') and local ('static')
******************************************************************************/

/******************************************************************************
** 功  能：CAN协议初始化函数
** 参  数：无
** 返回值：无
** 备  注：用于初始化CAN协议模块的相关变量，同时创建收发队列。
******************************************************************************/
void vPROTOCOL_Init(void)
{
    muilt_cyc_fifo_error_code_t    lxState;
    MCF_ApplyFifo(gxCAN_RxQueue_Len,gxCAN_RxQueue,&lxState);     /*初始化接收队列*/
    MCF_ApplyFifo(gxCAN_TxQueue_Len,gxCAN_TxQueue,&lxState);     /*初始化发送队列*/
    gxBikeInfo.Battery.SOC = -1;    /*该标志初始化为-1，用于判断是否接收到电池系统的SOC数据*/
    gxBikeInfo.MCU.MCU_SOC = -1;
    /*初始化仪表软、硬件版本号及序列号*/
    memcpy(gxBikeInfo.Display.Hard_Version_1,gucDisplay_Hard_Ver_1,8);
    memcpy(gxBikeInfo.Display.Hard_Version_2,gucDisplay_Hard_Ver_2,8);
    memcpy(gxBikeInfo.Display.Soft_Version_1,gucDisplay_Soft_Ver_1,8);
    memcpy(gxBikeInfo.Display.Soft_Version_2,gucDisplay_Soft_Ver_2,8);
    memcpy(gxBikeInfo.Display.SN_1,          gucDisplay_SN_1,      8);
    memcpy(gxBikeInfo.Display.SN_2,          gucDisplay_SN_2,      8);
    memcpy(gxBikeInfo.Display.SN_3,          gucDisplay_SN_3,      8);
}

/******************************************************************************
** 功  能：CAN发送函数
** 参  数：pCanMessage-指向要发送的数据结构体
** 返回值：无
** 备  注：
******************************************************************************/
static void vCAN_Transmit(strANANDA_CAN *pCanMessage)
{
    uint8_t n;
    can_tx_message_type    lxCanTxMessage;


    lxCanTxMessage.id_type      = CAN_ID_EXTENDED;      /*扩展帧*/
    lxCanTxMessage.frame_type   = CAN_TFT_DATA;         /*数据帧*/
    lxCanTxMessage.dlc          = 8;                    /*数据长度*/
    lxCanTxMessage.extended_id  = (pCanMessage->Priority << 26) | (pCanMessage->Reserver << 26) | (pCanMessage->Data_Page << 25)
                                  | (pCanMessage->PDU_Format << 16) | (pCanMessage->PS << 8) | pCanMessage->Source_Adress;

    for(n = 0; n < 8; n++)
    {
        lxCanTxMessage.data[n] = pCanMessage->Data[n];
    }

    /*调用发送函数进行发送*/
    can_message_transmit(CAN1,&lxCanTxMessage);
}

/******************************************************************************
** 功  能：将接收到的Can帧解析为安乃达的Can数据结构
** 参  数：pCanMessage-接收到的Can数据结构体指针
** 返回值：无
** 备  注：该函数是整个Can协议模块的入口函数。当CAN总线接收一帧Can数据后，调用该函数，
**        将Can消息帧转换为安乃达的CAN数据格式，并且放入接收队列
******************************************************************************/
void vCAN_CanMsgToANANDAMsg(can_rx_message_type *pCanMessage)
{
    strANANDA_CAN lxANANDA_CanMessage;
    muilt_cyc_fifo_error_code_t lxState;
    unsigned char n;

    lxANANDA_CanMessage.Source_Adress = pCanMessage->extended_id         & 0x000000FF;
    lxANANDA_CanMessage.PS            = (pCanMessage->extended_id >> 8)  & 0x000000FF;
    lxANANDA_CanMessage.PDU_Format    = (pCanMessage->extended_id >> 16) & 0x000000FF;
    lxANANDA_CanMessage.Data_Page     = (pCanMessage->extended_id >> 24) & 0x00000001;
    lxANANDA_CanMessage.Reserver      = (pCanMessage->extended_id >> 25) & 0x00000001;
    lxANANDA_CanMessage.Priority      = (pCanMessage->extended_id >> 26) & 0x00000007;

    for(n = 0; n < pCanMessage->dlc; n++)
    {
        lxANANDA_CanMessage.Data[n] = pCanMessage->data[n];
    }

    /*将转换后的Can数据放入FIFO队列*/
    MCF_WriteDataInFifo(gxCAN_RxQueue,(uint8_t *)&lxANANDA_CanMessage,sizeof(strANANDA_CAN),&lxState);
}




/******************************************************************************
** 功  能：CAN协议轮询，处理收发
** 参  数：无
** 返回值：无
** 备  注：该函数是模块主函数，应定时调用，调用周期一般10-20ms，定时处理收发
******************************************************************************/
void vPROTOCOL_Loop(void)
{
    static uint32_t lulTicks = 0;

    muilt_cyc_fifo_error_code_t lxState;
    uint16_t lxFifoCanReadLen;
    uint16_t lxActualReadLen;

    strANANDA_CAN       lxANANDA_CAN_RxMessage;
    strANANDA_CAN       lxANANDA_CAN_TxMessage;

    /*PGN：0x00FD01，开机时100ms发送一次，持续2秒*/
    if((lulTicks % (100 / CAN_LOOP_CYCLE) == 0) && lulTicks < 2000 / CAN_LOOP_CYCLE)
    {
        vCan_Send_DisplayMessage(0x00FD01,&gxBikeInfo);
    }
    /*接收到控制开机信号后，200ms发送一次的帧*/
    if(lulTicks % (200 / CAN_LOOP_CYCLE) == 0)
    {
        vCan_Send_DisplayMessage(0x00FD02,&gxBikeInfo);
    }

    /*1S发送一次的数据帧*/
    if(lulTicks % (1000 / CAN_LOOP_CYCLE) == 0)
    {
        vCan_Send_RequestPGN(ID_MCU,0x00FE07);
    }

    lulTicks++;
    gulCommunicationCnt++;

    /*10S之内，通信超时变量未复位，报30错误*/
    if(gulCommunicationCnt > (10000 / CAN_LOOP_CYCLE))
    {
        gxBikeInfo.ErrCode = 0x30;
        gxBikeInfo.MCU.Speed = 0;   /*报30错误时，强制把速度变为0*/
    }
    else
    {
        if(gxBikeInfo.ErrCode == 0x30)
        {
            gxBikeInfo.ErrCode = 0;
        }
    }

    /*判断接收队列是否非空*/
    MCF_GetCanReadLen(gxCAN_RxQueue,&lxFifoCanReadLen,&lxState);
    if(lxState == kMultiCycFiFo_Error_NONE && lxFifoCanReadLen > 0)
    {
        MCF_ReadDataFromFifo(gxCAN_RxQueue,sizeof(strANANDA_CAN),(uint8_t *)&lxANANDA_CAN_RxMessage,&lxActualReadLen,&lxState);/*从队列中取出一组CAN数据*/
        if(lxActualReadLen == sizeof(strANANDA_CAN) && lxState == kMultiCycFiFo_Error_NONE)
        {
            gulCommunicationCnt = 0;        /*复位通信超时计数*/
            /*判断目的节点*/
            switch(lxANANDA_CAN_RxMessage.Source_Adress)
            {
            case ID_MCU:          /*控制器发送的消息*/
            {
                vCAN_Receive_MCU_Message(&lxANANDA_CAN_RxMessage,&gxBikeInfo);
                break;
            }
            case ID_BMS_1:        /*主BMS发送的消息*/
            {
                vCAN_Receive_BMS_Message(&lxANANDA_CAN_RxMessage,&gxBikeInfo);
                break;
            }
            case ID_BMS_2:        /*副BMS发送的消息*/
            {
                break;
            }
            case ID_ABS:          /*ABS系统消息，暂不处理*/
            {
                break;
            }
            case ID_ANT:          /*ANT消息，暂不处理*/
            {
                break;
            }
            case ID_CHARGER:      /*充电器消息，暂不处理*/
            {
                break;
            }
            case ID_IOT:          /*IOT消息，暂不处理*/
            {
                break;
            }
            case ID_PSP:          /*PSP消息，暂不处理*/
            {
                break;
            }
            case ID_REMOTE:       /*REMOTE消息，暂不处理*/
            {
                break;
            }

            default:
                break;              /*其它消息不接收*/
            }
        }
    }

    /*判断发送缓冲区是否有数据需要发送*/
    MCF_GetCanReadLen(gxCAN_TxQueue,&lxFifoCanReadLen,&lxState);
    if(lxState == kMultiCycFiFo_Error_NONE && lxFifoCanReadLen > 0)
    {
        MCF_ReadDataFromFifo(gxCAN_TxQueue,sizeof(strANANDA_CAN),(uint8_t *)&lxANANDA_CAN_TxMessage,&lxActualReadLen,&lxState);/*从队列中取出一组CAN数据*/
        if(lxActualReadLen == sizeof(strANANDA_CAN) && lxState == kMultiCycFiFo_Error_NONE)
        {
            vCAN_Transmit(&lxANANDA_CAN_TxMessage);                          /*将安乃达CAN数据转换为实际的CAN帧，并发送*/
        }
    }
}

/******************************************************************************
** 功  能：接收处理源节点为控制器的消息
** 参  数：pBFCanMsg-接收到的Can消息指针，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
static void vCAN_Receive_MCU_Message(strANANDA_CAN *pCanMsg,strBikeInfo *pBikeInfo)
{
    uint8_t n;
    uint16_t lusTemp;
    uint32_t lulRequest_PGN;

    switch(pCanMsg->PS)
    {
    case 0x01:          /*PGN:0x00FE01,系统工作及匹配信息*/
    {
        pBikeInfo->MCU.Power            = pCanMsg->Data[0] >> 7;            /*是否开机信号*/
        pBikeInfo->MCU.Encryption_Type  = pCanMsg->Data[0] & 0x7F;          /*加密方式*/
        pBikeInfo->MCU.Key              = pCanMsg->Data[1];                 /*密钥*/
        pBikeInfo->MCU.Device_Type      = pCanMsg->Data[2] >> 5;            /*产品类型*/
        pBikeInfo->MCU.PowerUp_Type     = pCanMsg->Data[3] & 0x01;          /*开机启动方式*/
        pBikeInfo->MCU.User_SN          = ((uint16_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[4]; /*客户编码*/
        pBikeInfo->MCU.Vehicle_Type     = ((uint16_t)pCanMsg->Data[7] << 8) | pCanMsg->Data[6]; /*车辆型号*/
        break;
    }
    case 0x02:          /*PGN：0x00FE02，控制器数据1*/
    {
        pBikeInfo->MCU.Push             = (pCanMsg->Data[0] >> 5) & 0x03;   /*助推状态*/
        pBikeInfo->MCU.InSetting        = (pCanMsg->Data[0] >> 4) & 0x01;   /*仪表进设置状态标志*/
        pBikeInfo->MCU.Pas              = pCanMsg->Data[0]        & 0x0F;   /*档位*/
        pBikeInfo->MCU.Head_Lamp        = (pCanMsg->Data[1] >> 7);          /*前灯状态*/
        pBikeInfo->MCU.Rear_Lamp        = (pCanMsg->Data[1] >> 6) & 0x01;   /*后灯状态*/
        pBikeInfo->MCU.Trip_Clear       = (pCanMsg->Data[1] >> 5) & 0x01;   /*清Trip指令*/
        pBikeInfo->MCU.Auto_Lamp        = (pCanMsg->Data[1] >> 4) & 0x01;   /*自动大灯状态*/
        pBikeInfo->MCU.Display_RidingInfo = pCanMsg->Data[1] & 0x0F;        /*显示模式*/
        pBikeInfo->MCU.Button           = (pCanMsg->Data[2] >> 4) & 0x0F;   /*按键状态*/
        pBikeInfo->MCU.PowerOFF_Info    = (pCanMsg->Data[2] >> 2) & 0x03;   /*关机提示*/
        pBikeInfo->MCU.USB_Charging_En  = (pCanMsg->Data[2] >> 1) & 0x01;   /*USB充电是否允许*/
        pBikeInfo->MCU.Speed            = ((uint16_t)pCanMsg->Data[4] << 8) | pCanMsg->Data[3];   /*车速*/
        pBikeInfo->MCU.ErrCode          = pCanMsg->Data[5];                 /*故障码*/
        pBikeInfo->MCU.Drive_Mode       = (pCanMsg->Data[6] >> 6) & 0x03;   /* 模式*/
#if CAN_TYPE == TYPE_TUV
        /*当采用TUV模式时，仪表转发这些数据*/
        //pBikeInfo->Display.Push_En      = (pCanMsg->Data[0] >> 7) & 0x01;   /*助推是否使能*/
        pBikeInfo->Display.Push_State   = pBikeInfo->MCU.Push;              /*助推状态*/
        pBikeInfo->Display.InSetting    = pBikeInfo->MCU.InSetting;         /*是否在设置状态*/
        pBikeInfo->Display.Pas          = pBikeInfo->MCU.Pas;               /*档位*/

        pBikeInfo->Display.Head_Lamp    = pBikeInfo->MCU.Head_Lamp;         /*前灯状态*/
        pBikeInfo->Display.Rear_Lamp    = pBikeInfo->MCU.Rear_Lamp;         /*后灯状态*/
        pBikeInfo->Display.Auto_Lamp    = pBikeInfo->MCU.Auto_Lamp;         /*大灯控制模式*/
        pBikeInfo->Display.Display_RidingInfo = pBikeInfo->MCU.Display_RidingInfo;/*仪表显示模式*/
        pBikeInfo->Display.Drive_Mode   = pBikeInfo->MCU.Drive_Mode;        /*驱动模式*/

#endif
        break;
    }
    case 0x03:          /*PGN：0x00FE03，控制器数据2*/
    {
        pBikeInfo->MCU.Current          = pCanMsg->Data[0];                 /*母线实时电流*/
        pBikeInfo->MCU.Rpm              = pCanMsg->Data[1];                 /*脚踏转速*/
        pBikeInfo->MCU.Torque           = pCanMsg->Data[2];                 /*脚踏力矩*/
        pBikeInfo->MCU.Motor_Power      = ((uint16_t)pCanMsg->Data[4] << 8) | pCanMsg->Data[3]; /*电机功率*/
        pBikeInfo->MCU.Motor_Torque     = pCanMsg->Data[5];                 /*电机扭矩*/
        pBikeInfo->MCU.MCU_Temp         = pCanMsg->Data[6];                 /*控制器温度*/
        pBikeInfo->MCU.Motor_Temp       = pCanMsg->Data[7];                 /*电机温度*/
        break;
    }
    case 0x04:          /*PGN:0x00FE04，控制器数据3*/
    {
        pBikeInfo->MCU.ODO              = ((uint32_t)pCanMsg->Data[2] << 16) | ((uint32_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];    /*ODO*/
        pBikeInfo->MCU.Trip             = ((uint32_t)pCanMsg->Data[5] << 16) | ((uint32_t)pCanMsg->Data[4] << 8) | pCanMsg->Data[3];    /*Trip*/
        pBikeInfo->MCU.Range            = pCanMsg->Data[6];                 /*剩余里程*/
        pBikeInfo->MCU.Wheel_Size_Index = pCanMsg->Data[7];                 /*轮径索引值*/
        /*在满足控制器发回的Trip、最高速度都为0的情况下，再复位清Trip标志，增加一个最高速限制，可以防止在Trip为0时，选择清Trip，最高速不清零的问题*/
        if(pBikeInfo->MCU.Trip == 0  && pBikeInfo->MCU.Speed_Max == 0 && pBikeInfo->Display.Trip_Clear == 1)
        {
            pBikeInfo->Display.Trip_Clear = 0;  /*档清Trip标志为1，同时控制器发送的Trip值为0时，复位清Trip标志为0*/
        }
        break;
    }
    case 0x05:          /*PGN：0x00FE05，控制器数据4*/
    {
        pBikeInfo->MCU.Speed_Avg        = ((uint16_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];     /*平均速度*/
        pBikeInfo->MCU.Speed_Max        = ((uint16_t)pCanMsg->Data[3] << 8) | pCanMsg->Data[2];     /*最高速度*/
        pBikeInfo->MCU.Wheel_Length     = ((uint16_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[4];     /*车轮周长*/
        pBikeInfo->MCU.MCU_SOC          = pCanMsg->Data[6] >> 5;                                    /*控制器发送的SOC*/
        pBikeInfo->MCU.Limit_Current_Pas = pCanMsg->Data[7];                                        /*当前档位限流值*/
#if CAN_TYPE == TYPE_TUV
        /*当采用TUV模式时，仪表转发控制器发送的轮径值*/
        pBikeInfo->Display.Wheel_Length = pBikeInfo->MCU.Wheel_Length;
#endif
        break;
    }
    case 0x60:          /*PGN：0x00FE60，控制器参数1*/
    {
        /*该ID发送的是限速值，和0x00FE07中的参数重复，用那个？*/
        //pBikeInfo->MCU.Speed_Limit      = ((uint16_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];     /*限速值，0.1km/h*/
    }
    case 0x06:          /*PGN：0x00FE06，控制器信息1*/
    {
        pBikeInfo->MCU.Hard_Version_Num = ((uint16_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];     /*硬件版本号*/
        pBikeInfo->MCU.Soft_Version_Num = ((uint16_t)pCanMsg->Data[3] << 8) | pCanMsg->Data[2];     /*软件版本号*/
        lusTemp = ((uint16_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[4];
        pBikeInfo->MCU.Production_Date.Year  = lusTemp >> 9;                                        /*生产日期，年*/
        pBikeInfo->MCU.Production_Date.Month = (lusTemp >> 5) & 0x000F;                             /*生产日期，月*/
        pBikeInfo->MCU.Production_Date.Day   = lusTemp & 0x001F;                                    /*生产日期，日*/
        pBikeInfo->MCU.SN_Num                = ((uint16_t)pCanMsg->Data[7] << 8) | pCanMsg->Data[6];/*产品流水号*/
        break;
    }
    case 0x07:          /*PGN：0x00FE07，控制器数据5*/
    {
        pBikeInfo->MCU.Riding_Time      = pCanMsg->Data[1] * 60UL + pCanMsg->Data[0];               /*骑行时间，分钟*/
        pBikeInfo->MCU.Speed_Limit      = ((uint16_t)pCanMsg->Data[4] << 8) | pCanMsg->Data[3];     /*限速值，0.1km/h*/
        break;
    }
    case 0x09:          /*PGN:0x00FE08,控制器数据6*/
    {
        pBikeInfo->MCU.Human_Power            = ((uint16_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];     /*骑行功率*/
        pBikeInfo->MCU.Motor_Consumption      = ((uint16_t)pCanMsg->Data[3] << 8) | pCanMsg->Data[2];    /*电机顺时功耗*/
        pBikeInfo->MCU.Motor_Trip_Consumption = ((uint16_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[4];    /*电机平均功耗*/
        pBikeInfo->MCU.Motor_Power_State      = pCanMsg->Data[6];                                        /*降功率状态*/
        break;
    }
    case 0x10:          /*PGN：0x00FE10，控制器硬件版本1，ASCII字符*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->MCU.Hard_Version_1[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x11:          /*PGN：0x00FE11，控制器硬件版本2，ASCII字符*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->MCU.Hard_Version_2[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x15:          /*PGN：0x00FE15，控制器软件版本1，ASCII字符*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->MCU.Soft_Version_1[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x16:          /*PGN：0x00FE16，控制器软件版本2，ASCII字符*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->MCU.Soft_Version_2[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x1A:          /*PGN：0x00FE1A，控制器序列号1，ASCII字符*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->MCU.SN_1[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x1B:          /*PGN：0x00FE1B，控制器序列号2，ASCII字符*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->MCU.SN_2[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x1C:          /*PGN：0x00FE1C，控制器序列号3，ASCII字符*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->MCU.SN_3[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x20:          /*PGN：0x00FE20，控制器参数版本1，ASCII字符*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->MCU.Parameter_1[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x21:          /*PGN：0x00FE21，控制器参数版本2，ASCII字符*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->MCU.Parameter_2[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x22:          /*PGN：0x00FE22，控制器参数版本3，ASCII字符*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->MCU.Parameter_3[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x25:          /*PGN：0x00FE25，控制器客户代码1，ASCII字符*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->MCU.User_ID_1[n]= pCanMsg->Data[n];
        }
        break;
    }
    case 0x26:          /*PGN：0x00FE26，控制器客户代码2，ASCII字符*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->MCU.User_ID_2[n]= pCanMsg->Data[n];
        }
        break;
    }
    case 0x28:          /*此处0x28为仪表ID，表示目的地址是仪表的报文*/
    {
        if(pCanMsg->PDU_Format == 0xEA) /*PGN请求报文*/
        {
            lulRequest_PGN = ((uint32_t)pCanMsg->Data[2] << 16) | ((uint32_t)pCanMsg->Data[1] << 8) | ((uint32_t)pCanMsg->Data[0]);
            vCan_Send_DisplayMessage(lulRequest_PGN,&gxBikeInfo);       /*根据请求的PGN，发送对应消息*/
        }
    }
    default:
    {
        break;
    }
    }
}

/******************************************************************************
** 功  能：接收处理源节点为BMS的消息
** 参  数：pBFCanMsg-接收到的Can消息指针，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
static void vCAN_Receive_BMS_Message(strANANDA_CAN *pCanMsg,strBikeInfo *pBikeInfo)
{
    uint8_t n;
    uint16_t lusTemp;
    switch(pCanMsg->PS)
    {
    case 0x25:      /*PGN：0x00FF25，BMS匹配信息*/
    {
        pBikeInfo->Battery.Power            = (pCanMsg->Data[0] >> 7) & 0x01;       /*开机标志*/
        pBikeInfo->Battery.Encryption_Type  = pCanMsg->Data[0] & 0x7F;              /*加密方式*/
        pBikeInfo->Battery.Key              = pCanMsg->Data[1];                     /*密钥*/
        pBikeInfo->Battery.Device_Type      = ((uint16_t)pCanMsg->Data[3] << 8) | pCanMsg->Data[2]; /*产品类型*/
        pBikeInfo->Battery.User_SN          = ((uint16_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[4]; /*客户编码*/
        pBikeInfo->Battery.Vehicle_Type     = ((uint16_t)pCanMsg->Data[7] << 8) | pCanMsg->Data[6]; /*车辆型号*/
        break;
    }
    case 0x01:      /*PGN：0x00FF01，电池组温度*/
    {
        pBikeInfo->Battery.Temp_Num         = pCanMsg->Data[0];                     /*温度探头数量*/
        for(n = 0; n < pBikeInfo->Battery.Temp_Num; n++)
        {
            pBikeInfo->Battery.Temp[n] = pCanMsg->Data[n];                          /*各探头温度*/
        }
        break;
    }
    case 0x02:      /*PGN：0x00FF02，电池组综合数据*/
    {
        pBikeInfo->Battery.SOH              = pCanMsg->Data[0];
        pBikeInfo->Battery.SOC              = pCanMsg->Data[1];
        pBikeInfo->Battery.Capacity_Remain  = ((uint16_t)pCanMsg->Data[3] << 8) | pCanMsg->Data[2]; /*剩余容量*/
        pBikeInfo->Battery.Capacity_Full    = ((uint16_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[4]; /*剩余容量*/
        pBikeInfo->Battery.Capacity_Design  = ((uint16_t)pCanMsg->Data[7] << 8) | pCanMsg->Data[6]; /*剩余容量*/
        break;
    }
    case 0x03:      /*PGN：0x00FF03，电芯电压1*/
    {
        pBikeInfo->Battery.Cell_Num_Serial   = pCanMsg->Data[0];                     /*电池组串数*/
        pBikeInfo->Battery.Cell_Num_Parallel = pCanMsg->Data[1];                     /*电池组并数*/
        for(n = 0; n < 3; n++)
        {
            pBikeInfo->Battery.Cell_Volt[n] = ((uint16_t)pCanMsg->Data[3 + 2 * n] << 8) | pCanMsg->Data[2 + 2 * n]; /*电芯1-3电压*/
        }
        break;
    }
    case 0x04:      /*PGN：0x00FF04，电芯电压2*/
    {
        for(n = 0; n < 4; n++)
        {
            pBikeInfo->Battery.Cell_Volt[3 + n] = ((uint16_t)pCanMsg->Data[1 + 2 * n] << 8) | pCanMsg->Data[2 * n]; /*电芯4-7*/
        }
        break;
    }
    case 0x05:      /*PGN：0x00FF05，电芯电压3*/
    {
        for(n = 0; n < 4; n++)
        {
            pBikeInfo->Battery.Cell_Volt[7 + n] = ((uint16_t)pCanMsg->Data[1 + 2 * n] << 8) | pCanMsg->Data[2 * n]; /*电芯8-11*/
        }
        break;
    }
    case 0x06:      /*PGN：0x00FF06，电芯电压4*/
    {
        for(n = 0; n < 4; n++)
        {
            pBikeInfo->Battery.Cell_Volt[11 + n] = ((uint16_t)pCanMsg->Data[1 + 2 * n] << 8) | pCanMsg->Data[2 * n]; /*电芯12-15*/
        }
        break;
    }
    case 0x0A:      /*PGN：0x00FF0A，电池组实时电压电流*/
    {
        pBikeInfo->Battery.Voltage          = ((uint16_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];     /*电池组电压*/
        pBikeInfo->Battery.Current          = ((uint16_t)pCanMsg->Data[3] << 8) | pCanMsg->Data[2];     /*电池组电流*/
        pBikeInfo->Battery.MaxCurrent_Continued = pCanMsg->Data[4];                                     /*最大允许持续电流*/
        pBikeInfo->Battery.MaxCurrent_Peak      = pCanMsg->Data[5];                                     /*最大允许峰值电流*/
        pBikeInfo->Battery.MaxCurrent_Charge    = pCanMsg->Data[6];                                     /*最大允许充电电流*/
        pBikeInfo->Battery.Power_Scale          = pCanMsg->Data[7];                                     /*系统功率输入系数*/
        break;
    }
    case 0x0B:      /*PGN：0x00FF0B，电池组警告和保护*/
    {
        pBikeInfo->Battery.AlarmInfo        = ((uint32_t)pCanMsg->Data[3] << 24) | ((uint32_t)pCanMsg->Data[2] << 16) | ((uint32_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];/*警告信息*/
        pBikeInfo->Battery.ProtectInfo      = ((uint32_t)pCanMsg->Data[7] << 24) | ((uint32_t)pCanMsg->Data[6] << 16) | ((uint32_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[4];/*警告信息*/
        break;
    }
    case 0x0C:      /*PGN：0x00FF0C，电池组状态*/
    {
        pBikeInfo->Battery.Charge_State     = pCanMsg->Data[0];         /*充电状态*/
        pBikeInfo->Battery.Discharge_State  = pCanMsg->Data[1];         /*放电状态*/
        pBikeInfo->Battery.Charge_Flag      = pCanMsg->Data[2];         /*状态标记*/
        break;
    }
    case 0x10:      /*PGN：0x00FF10，电池组记录数据*/
    {
        pBikeInfo->Battery.Cycle_Times                = ((uint16_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];   /*循环次数*/
        pBikeInfo->Battery.Charging_Time_Interval     = ((uint16_t)pCanMsg->Data[3] << 8) | pCanMsg->Data[2];   /*充电时间间隔*/
        pBikeInfo->Battery.Charging_Time_Interval_Max = ((uint16_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[4];   /*最大充电时间间隔*/
        pBikeInfo->Battery.Active_Time                = ((uint16_t)pCanMsg->Data[7] << 8) | pCanMsg->Data[6];   /*激活时间*/
        break;
    }
    case 0x0D:      /*PGN：0x00FF0D，电池故障信息*/
    {
        if(pCanMsg->Data[4] > 0)
        {
            pBikeInfo->Battery.FaultCode    = ((uint32_t)pCanMsg->Data[7] << 16) | ((uint32_t)pCanMsg->Data[6] << 8) | pCanMsg->Data[5];    /*电池故障码*/
        }
        else
        {
            pBikeInfo->Battery.FaultCode    = 0x00;
        }
        break;
    }
    case 0x15:      /*PGN：0x00FF15，电池组条码*/
    {
        pBikeInfo->Battery.ID_Num       = pCanMsg->Data[0];     /*条码长度*/
        for(n = 0; n < 7; n++)
        {
            pBikeInfo->Battery.ID[n] = pCanMsg->Data[1 + n];    /*条码*/
        }
        break;
    }
    case 0x16:      /*PGN，0x00FF16，电池组条码2*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->Battery.ID[7 + n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x17:      /*PGN，0x00FF17，电池组条码3*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->Battery.ID[15 + n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x18:      /*PGN，0x00FF18，电池组条码4*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->Battery.ID[23 + n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x20:      /*PGN，0x00FF20，电池软件版本号1*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->Battery.Soft_Version_1[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x21:      /*PGN，0x00FF21，电池硬件版本号1*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->Battery.Hard_Version_1[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x22:      /*PGN，0x00FF22，电池硬件版本号2*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->Battery.Hard_Version_2[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x24:      /*PGN，0x00FF24，电池RTC*/
    {
        lusTemp = ((uint16_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];
        pBikeInfo->Battery.RTC_Time.Year     = (lusTemp >> 9);               /*年*/
        pBikeInfo->Battery.RTC_Time.Month    = (lusTemp >> 5) & 0x0F;        /*月*/
        pBikeInfo->Battery.RTC_Time.Day      = lusTemp & 0x1F;               /*日*/
        pBikeInfo->Battery.RTC_Time.Hour     = pCanMsg->Data[2];             /*小时*/
        pBikeInfo->Battery.RTC_Time.Min      = pCanMsg->Data[3];             /*分钟*/
        pBikeInfo->Battery.RTC_Time.Sec      = pCanMsg->Data[4];             /*秒*/
        lusTemp = ((uint16_t)pCanMsg->Data[6] << 8) | pCanMsg->Data[5]; /*上次校准时间*/
        pBikeInfo->Battery.RTC_LastCalibration.Year  = (lusTemp >> 9);
        pBikeInfo->Battery.RTC_LastCalibration.Month = (lusTemp >> 5) & 0x0F;
        pBikeInfo->Battery.RTC_LastCalibration.Day   = lusTemp & 0x1F;
        break;
    }
    }
}

/******************************************************************************
** 功  能：仪表发送消息
** 参  数：PGN-要发送的PGN号，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
static void vCan_Send_DisplayMessage(uint32_t PGN,strBikeInfo   *pBikeInfo)
{
    strANANDA_CAN   lxCanTxMsg;
    muilt_cyc_fifo_error_code_t lxState;
    uint16_t lusTemp;

    switch(PGN)
    {
    case 0x00FD01:/*仪表匹配消息*/
    {
        lxCanTxMsg.Data[0] = (pBikeInfo->Display.Power << 7) | pBikeInfo->Display.Encryption_Type;
        lxCanTxMsg.Data[1] = pBikeInfo->Display.Key;
        lxCanTxMsg.Data[2] = pBikeInfo->Display.Device_Type;
        lxCanTxMsg.Data[3] = pBikeInfo->Display.PowerUp_Type;
        lxCanTxMsg.Data[4] = pBikeInfo->Display.User_SN & 0x0F;
        lxCanTxMsg.Data[5] = pBikeInfo->Display.User_SN >> 8;
        lxCanTxMsg.Data[6] = pBikeInfo->Display.Vehicle_Type & 0x0F;
        lxCanTxMsg.Data[7] = pBikeInfo->Display.Vehicle_Type >> 8;
        break;
    }
    case 0x00FD02:/*仪表主要数据，200ms周期发送*/
    {
        lxCanTxMsg.Data[0] = (pBikeInfo->Display.Push_En << 7) | (pBikeInfo->Display.Push_State << 5) | (pBikeInfo->Display.InSetting << 4) | (pBikeInfo->Display.Pas);
        lxCanTxMsg.Data[1] = (pBikeInfo->Display.Head_Lamp << 7) | (pBikeInfo->Display.Rear_Lamp << 6) | (pBikeInfo->Display.Trip_Clear << 5) | (pBikeInfo->Display.Auto_Lamp << 4) | (pBikeInfo->Display.Display_RidingInfo);
        lxCanTxMsg.Data[2] = pBikeInfo->Display.Wheel_Length & 0x0F;
        lxCanTxMsg.Data[3] = pBikeInfo->Display.Wheel_Length >> 8;
        lxCanTxMsg.Data[4] = pBikeInfo->Display.ErrCode;
        lxCanTxMsg.Data[5] = (pBikeInfo->Display.Speed_Limit_Type << 4) | (pBikeInfo->Display.Button & 0x0F);  /*此处关于车速模式有疑问*/
        lxCanTxMsg.Data[6] = pBikeInfo->Display.Drive_Mode << 6;
        lxCanTxMsg.Data[7] = (pBikeInfo->Display.Battery_Lamp << 7) | (pBikeInfo->Display.Left_Lamp << 6) | (pBikeInfo->Display.Right_Lamp << 5);
        break;
    }
    case 0x00FD03:/*仪表版本/SN码*/
    {
        lxCanTxMsg.Data[0] = pBikeInfo->Display.Hard_Version_Num & 0x00FF;
        lxCanTxMsg.Data[1] = pBikeInfo->Display.Hard_Version_Num >> 8;
        lxCanTxMsg.Data[2] = pBikeInfo->Display.Soft_Version_Num & 0x00FF;
        lxCanTxMsg.Data[3] = pBikeInfo->Display.Soft_Version_Num >> 8;
        lusTemp            = ((uint16_t)pBikeInfo->Display.Production_Date.Year << 9) | ((uint16_t)pBikeInfo->Display.Production_Date.Month << 5) | ((uint16_t)pBikeInfo->Display.Production_Date.Day & 0x001F);
        lxCanTxMsg.Data[4] = lusTemp & 0x00FF;
        lxCanTxMsg.Data[5] = lusTemp >> 8;
        lxCanTxMsg.Data[6] = pBikeInfo->Display.SN_Num & 0x00FF;
        lxCanTxMsg.Data[7] = pBikeInfo->Display.SN_Num >> 8;
        break;
    }
    case 0x00FD10:/*仪表硬件版本1*/
    {
        for(lusTemp = 0; lusTemp < 8; lusTemp++)
        {
            lxCanTxMsg.Data[lusTemp] = pBikeInfo->Display.Hard_Version_1[lusTemp];
        }
        break;
    }
    case 0x00FD11:/*仪表硬件版本2*/
    {
        for(lusTemp = 0; lusTemp < 8; lusTemp++)
        {
            lxCanTxMsg.Data[lusTemp] = pBikeInfo->Display.Hard_Version_2[lusTemp];
        }
        break;
    }
    case 0x00FD15:/*仪表软件版本1*/
    {
        for(lusTemp = 0; lusTemp < 8; lusTemp++)
        {
            lxCanTxMsg.Data[lusTemp] = pBikeInfo->Display.Soft_Version_1[lusTemp];
        }
        break;
    }
    case 0x00FD16:/*仪表软件版本2*/
    {
        for(lusTemp = 0; lusTemp < 8; lusTemp++)
        {
            lxCanTxMsg.Data[lusTemp] = pBikeInfo->Display.Soft_Version_2[lusTemp];
        }
        break;
    }
    case 0x00FD1A:/*仪表序列号1*/
    {
        for(lusTemp = 0; lusTemp < 8; lusTemp++)
        {
            lxCanTxMsg.Data[lusTemp] = pBikeInfo->Display.SN_1[lusTemp];
        }
        break;
    }
    case 0x00FD1B:/*仪表序列号2*/
    {
        for(lusTemp = 0; lusTemp < 8; lusTemp++)
        {
            lxCanTxMsg.Data[lusTemp] = pBikeInfo->Display.SN_2[lusTemp];
        }
        break;
    }
    case 0x00FD1C:/*仪表序列号3*/
    {
        for(lusTemp = 0; lusTemp < 8; lusTemp++)
        {
            lxCanTxMsg.Data[lusTemp] = pBikeInfo->Display.SN_3[lusTemp];
        }
        break;
    }
    }

    lxCanTxMsg.Data_Page     = 0x00;
    lxCanTxMsg.Priority      = 0x06;
    lxCanTxMsg.Reserver      = 0x00;
    lxCanTxMsg.PDU_Format    = (PGN >> 8) & 0x000000FF;
    lxCanTxMsg.PS            = (PGN & 0x000000FF);
    lxCanTxMsg.Source_Adress = (uint8_t)ID_DP;

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxMsg,sizeof(strANANDA_CAN),&lxState); /*将数据放入发送队列，排队发送*/
}

/******************************************************************************
** 功  能：仪表向节点发送PGN请求
** 参  数：Dst_ID-目的节点地址，PGN-要请求的PGN号
** 返回值：无
** 备  注：
******************************************************************************/
void vCan_Send_RequestPGN(enuDEVICE_ID Dst_ID,uint32_t PGN)
{
    strANANDA_CAN   lxCanTxMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lxCanTxMsg.Priority      = 6;
    lxCanTxMsg.Reserver      = 0;
    lxCanTxMsg.Data_Page     = 0;
    lxCanTxMsg.PDU_Format    = 0xEA;            /*请求PGN专用PF*/
    lxCanTxMsg.PS            = (uint8_t)Dst_ID;
    lxCanTxMsg.Source_Adress = (uint8_t)ID_DP;  /*源地址是仪表*/
    lxCanTxMsg.Data[0]       = PGN;
    lxCanTxMsg.Data[1]       = PGN >> 8;
    lxCanTxMsg.Data[2]       = PGN >> 16;
    lxCanTxMsg.Data[3]       = 0x00;
    lxCanTxMsg.Data[4]       = 0x00;
    lxCanTxMsg.Data[5]       = 0x00;
    lxCanTxMsg.Data[6]       = 0x00;
    lxCanTxMsg.Data[7]       = 0x00;
    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxMsg,sizeof(strANANDA_CAN),&lxState); /*将数据放入发送队列，排队发送*/
}

/******************************************************************************
** 功  能：仪表设置限速值
** 参  数：LimitSpeed-限速值，0.1km/h
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_LimitSpeed(uint16_t LimitSpeed)
{
    strANANDA_CAN   lxCanTxMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lxCanTxMsg.Data_Page     = 0x00;
    lxCanTxMsg.Priority      = 0x06;
    lxCanTxMsg.Reserver      = 0x00;
    lxCanTxMsg.PDU_Format    = 0x60;
    lxCanTxMsg.PS            = 0xEF;
    lxCanTxMsg.Source_Adress = (uint8_t)ID_DP;
    lxCanTxMsg.Data[0]       = 0x55;    /*索引号：0x0055，表示设置限速*/
    lxCanTxMsg.Data[1]       = 0x00;
    lxCanTxMsg.Data[2]       = 0x02;    /*参数长度，2字节*/
    lxCanTxMsg.Data[3]       = LimitSpeed;
    lxCanTxMsg.Data[4]       = LimitSpeed >> 8;
    lxCanTxMsg.Data[5]       = 0;
    lxCanTxMsg.Data[6]       = 0;
    lxCanTxMsg.Data[7]       = lxCanTxMsg.Data[0] + lxCanTxMsg.Data[1] + lxCanTxMsg.Data[2] + lxCanTxMsg.Data[3] +
                               lxCanTxMsg.Data[4] + lxCanTxMsg.Data[5] + lxCanTxMsg.Data[6];

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxMsg,sizeof(strANANDA_CAN),&lxState); /*将数据放入发送队列，排队发送*/
}

/******************************************************************************
** 功  能：仪表设置轮周长
** 参  数：WheelLength-轮周长，mm
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_WheelLength(uint16_t WheelLength)
{
    strANANDA_CAN   lxCanTxMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lxCanTxMsg.Data_Page     = 0x00;
    lxCanTxMsg.Priority      = 0x06;
    lxCanTxMsg.Reserver      = 0x00;
    lxCanTxMsg.PDU_Format    = 0x60;
    lxCanTxMsg.PS            = 0xEF;
    lxCanTxMsg.Source_Adress = (uint8_t)ID_DP;
    lxCanTxMsg.Data[0]       = 0x40;    /*索引号：0x0040，表示设置轮周长*/
    lxCanTxMsg.Data[1]       = 0x00;
    lxCanTxMsg.Data[2]       = 0x02;    /*参数长度，2字节*/
    lxCanTxMsg.Data[3]       = WheelLength;
    lxCanTxMsg.Data[4]       = WheelLength >> 8;
    lxCanTxMsg.Data[5]       = 0;
    lxCanTxMsg.Data[6]       = 0;
    lxCanTxMsg.Data[7]       = lxCanTxMsg.Data[0] + lxCanTxMsg.Data[1] + lxCanTxMsg.Data[2] + lxCanTxMsg.Data[3] +
                               lxCanTxMsg.Data[4] + lxCanTxMsg.Data[5] + lxCanTxMsg.Data[6];

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxMsg,sizeof(strANANDA_CAN),&lxState); /*将数据放入发送队列，排队发送*/
}


/******************************************************************************
** 功  能：仪表设置轮径
** 参  数：Wheel-轮径，0.1inch
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Wheel(uint16_t Wheel)
{
    strANANDA_CAN   lxCanTxMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lxCanTxMsg.Data_Page     = 0x00;
    lxCanTxMsg.Priority      = 0x06;
    lxCanTxMsg.Reserver      = 0x00;
    lxCanTxMsg.PDU_Format    = 0x60;
    lxCanTxMsg.PS            = 0xEF;
    lxCanTxMsg.Source_Adress = (uint8_t)ID_DP;
    lxCanTxMsg.Data[0]       = 0x41;    /*索引号：0x0041，表示设置轮径*/
    lxCanTxMsg.Data[1]       = 0x00;
    lxCanTxMsg.Data[2]       = 0x02;    /*参数长度，2字节*/
    lxCanTxMsg.Data[3]       = Wheel;
    lxCanTxMsg.Data[4]       = Wheel >> 8;
    lxCanTxMsg.Data[5]       = 0;
    lxCanTxMsg.Data[6]       = 0;
    lxCanTxMsg.Data[7]       = lxCanTxMsg.Data[0] + lxCanTxMsg.Data[1] + lxCanTxMsg.Data[2] + lxCanTxMsg.Data[3] +
                               lxCanTxMsg.Data[4] + lxCanTxMsg.Data[5] + lxCanTxMsg.Data[6];

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxMsg,sizeof(strANANDA_CAN),&lxState); /*将数据放入发送队列，排队发送*/
}


/******************************************************************************
** 功  能：设置仪表开机标志位
** 参  数：State-仪表状态。0-关闭，1-打开
** 返回值：无
** 备  注：安乃达CAN协议，18FD0128用
******************************************************************************/
void vPROTOCOL_Set_Power(uint8_t State)
{
    gxBikeInfo.Display.Power = State;
}

/******************************************************************************
** 功  能：设置当前显示模式
** 参  数：State-当前显示模式，0-Trip，1-ODO，2-Range,3-AVG，4-MAX，
** 返回值：无
** 备  注：安乃达CAN协议，18FD0228用
******************************************************************************/
void vPROTOCOL_Set_Display_RidingInfo(uint8_t State)
{
    if(State < 3)
    {
        gxBikeInfo.Display.Display_RidingInfo = State;
    }
    else
    {
        gxBikeInfo.Display.Display_RidingInfo = (State - 2) << 2;
    }
}

/******************************************************************************
** 功  能：设置按键状态
** 参  数：KeyValue-按键值
** 返回值：无
** 备  注：安乃达CAN协议，18FD0228用
******************************************************************************/
void vPROTOCOL_Set_Button(uint8_t KeyValue)
{
    /*UP键*/
    if(KeyValue & 0x01)
    {
        gxBikeInfo.Display.Button |= 0x08;
    }
    else
    {
        gxBikeInfo.Display.Button &= 0xF7;
    }

    /*DOWN键*/
    if(KeyValue & 0x04)
    {
        gxBikeInfo.Display.Button |= 0x04;
    }
    else
    {
        gxBikeInfo.Display.Button &= 0xFB;
    }

    /*POWER键*/
    if(KeyValue & 0x08)
    {
        gxBikeInfo.Display.Button |= 0x02;
    }
    else
    {
        gxBikeInfo.Display.Button &= 0xFD;
    }

    /*MODE键*/
    if(KeyValue & 0x02)
    {
        gxBikeInfo.Display.Button |= 0x01;
    }
    else
    {
        gxBikeInfo.Display.Button &= 0xFE;
    }

}

/******************************************************************************
** 功  能：设置大灯状态
** 参  数：State-大灯状态。0-关闭，1-打开
** 返回值：无
** 备  注：所有协议通用
******************************************************************************/
void vPROTOCOL_Set_Lamp(uint8_t State)
{
    gxBikeInfo.Display.Head_Lamp = State;/*前灯状态*/
    gxBikeInfo.Display.Rear_Lamp = State;/*后灯状态*/
}

/******************************************************************************
** 功  能：设置档位范围
** 参  数：Pas_Range
** 返回值：无
** 备  注：安乃达控制器，默认支持5个挡位，当选择3档位时，发送1、3、5档
**         特殊7档和9档的，需要更改控制器程序，暂不考虑
******************************************************************************/
void vPROTOCOL_Set_Pas_Range(int8_t Pas_Range)
{
    gxBikeInfo.Display.Pas_Range = Pas_Range;
}

/******************************************************************************
** 功  能：设置档位
** 参  数：Pas-档位值，最大为9，最小为-1,-1表示助推档
** 返回值：无
** 备  注：本函数在仪表为主机的模式下可用，在TUV模式下，仪表发送的档位是转发控制器的数据
**         不要调用该函数
**         安乃达控制器，默认支持5个挡位，当选择3档位时，发送1、3、5档
**         特殊7档和9档的，需要更改控制器程序，暂不考虑
******************************************************************************/
void vPROTOCOL_Set_Pas(int8_t Pas)
{
    /*此处对于安乃达协议的助推尚有疑问，是否这样处理，需要控制器验证*/
    if(Pas > -1)
    {
        gxBikeInfo.Display.Push_En    = 0;  /*禁止推行*/
        gxBikeInfo.Display.Push_State = 0;  /*推行状态设为未启动*/
        gxBikeInfo.Display.Pas = Pas;       /*5挡位的话，按照实际挡位发送*/
    }
    else
    {
        gxBikeInfo.Display.Push_En    = 1;  /*推行使能*/
        gxBikeInfo.Display.Push_State = 2;  /*推行状态设为工作状态*/
    }
}

/******************************************************************************
** 功  能：设置助推允许
** 参  数：En-0,禁止助推，1-允许助推
** 返回值：无
** 备  注：本函数为TUV模式下调用的函数，告诉控制器进助推预触发。
******************************************************************************/
void vPROTOCOL_Set_Push_En(uint8_t En)
{
    gxBikeInfo.Display.Push_En = En;
}



/******************************************************************************
** 功  能：设置仪表是否进入设置状态
** 参  数：State-状态，0-未进入设置，1-进入设置
** 返回值：无
** 备  注：本函数在仪表为主机的模式下可用，在TUV模式下，仪表发送的是转发控制器的数据
**         不要调用该函数
******************************************************************************/
void vPROTOCOL_Set_InSetting(uint8_t State)
{
    gxBikeInfo.Display.InSetting = State;
}

/******************************************************************************
** 功  能：设置清Trip
** 参  数：State-是否清Trip，0-不清，1-清Trip
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_ClearTrip(uint8_t State)
{
    gxBikeInfo.Display.Trip_Clear = State;
}



/******************************************************************************
** 功  能：设置发送一次配置数据
** 参  数：无
** 返回值：无
** 备  注：本函数运行后，只发送一次配置数据。然后会转为发送运行数据
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Send_Config_Data_OneTime(void)
{

}

/******************************************************************************
** 功  能：停止发送数据
** 参  数：无
** 返回值：无
** 备  注：本函数运行后，即停止发送数据。直到再次设置发送配置数据或发送运行数据
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Send_Stop(void)
{

}

/******************************************************************************
** 功  能：获取电量等级
** 参  数：无
** 返回值：电量等级。0-表示欠压，1-5表示电量等级
** 备  注：J协议用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Volt_Level(void)
{
    return 0;
}

/******************************************************************************
** 功  能：获取当前电流值
** 参  数：无
** 返回值：实际电流值的10倍。比如实际电流12.3A，返回123
** 备  注：所有协议通用
******************************************************************************/
uint16_t usPROTOCOL_Get_Current(void)
{
    return gxBikeInfo.MCU.Current;
}

/******************************************************************************
** 功  能：获取电池容量
** 参  数：无
** 返回值：-1表示未获取到电池容量，电池容量，0-100%
** 备  注：
******************************************************************************/
int8_t cPROTOCOL_Get_Soc(void)
{
    if(gxBikeInfo.Battery.SOC > -1)
    {
        if(gxBikeInfo.Battery.SOC > 100)
        {
            return 100;
        }
        else
        {
            return gxBikeInfo.Battery.SOC;  /*读取到了BMS的SOC，返回SOC*/
        }
    }
//    else if(gxBikeInfo.MCU.MCU_SOC > -1)
//    {
//        if(gxBikeInfo.MCU.MCU_SOC > 5)
//        {
//            return 100;
//        }
//        else
//        {
//            return gxBikeInfo.MCU.MCU_SOC * 20;/*没有读取到BMS的SOC，但是读取到了控制器的电量等级，（0-5），返回对应的SOC（0%，20%，40%，60%，80%，100%）*/
//        }
//    }
    else
    {
        return -1;/*BMS和控制器的SOC都没有读取到，返回-1*/
    }
}


/******************************************************************************
** 功  能：获取当前车速
** 参  数：无
** 返回值：实际车速*10.比如返回120，实际车速即12.0Km/h
** 备  注：所有协议通用
******************************************************************************/
uint16_t usPROTOCOL_Get_Speed(void)
{
    return gxBikeInfo.MCU.Speed;
}

/******************************************************************************
** 功  能：获取错误代码
** 参  数：无
** 返回值：十六进制的错误代码
** 备  注：包括30错误代码（通信超时）
**         所有协议通用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Errcode(void)
{
    uint8_t n;
    const uint8_t AND_ErrCodeTab[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x08,0x09,0x10,0x30,0x31,0x36,0x37,0x38,0x40,0x41,0x42,0x43,0x50};

    if(gxBikeInfo.ErrCode > 0)
    {
        return gxBikeInfo.ErrCode;
    }
    else
    {
        for(n = 0; n < sizeof(AND_ErrCodeTab) / sizeof(uint8_t); n++)
        {
            if(gxBikeInfo.MCU.ErrCode == AND_ErrCodeTab[n])
            {
                break;
            }
        }
        if(n == sizeof(AND_ErrCodeTab) / sizeof(uint8_t))
        {
            return 0;       /*只报协议中规定的代码。其它代码返回0*/
        }
        else
        {
            return gxBikeInfo.MCU.ErrCode;
        }

    }

}

/******************************************************************************
** 功  能：获取TRIP里程
** 参  数：无
** 返回值：TRIP值，0.1Km
** 备  注：
******************************************************************************/
uint32_t ulPROTOCOL_Get_Trip(void)
{
    return gxBikeInfo.MCU.Trip;
}

/******************************************************************************
** 功  能：获取显示的轮径索引值
** 参  数：无
** 返回值：轮径英寸值×10，比如27寸，返回270，700C返回275
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Wheel(void)
{
    const uint16_t WheelTab[] = {0,80,100,120,140,160,180,200,220,240,260,270,275,280,290};

    return WheelTab[gxBikeInfo.MCU.Wheel_Size_Index];
}

/******************************************************************************
** 功  能：获取轮径长度（mm）
** 参  数：无
** 返回值：轮径长度，单位mm
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Wheel_Lenght(void)
{
    return gxBikeInfo.MCU.Wheel_Length;
}

/******************************************************************************
** 功  能：获取限速值
** 参  数：无
** 返回值：限速值，0.1km/h
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Speed_Limit(void)
{
    return gxBikeInfo.MCU.Speed_Limit;
}

/******************************************************************************
** 功  能：获取ODO里程
** 参  数：无
** 返回值：ODO值，0.1Km
** 备  注：
******************************************************************************/
uint32_t ulPROTOCOL_Get_Odo(void)
{
    return gxBikeInfo.MCU.ODO;
}

/******************************************************************************
** 功  能：获取剩余里程
** 参  数：无
** 返回值：剩余里程，Range值，1Km
** 备  注：
******************************************************************************/
uint8_t usPROTOCOL_Get_Range(void)
{
    return gxBikeInfo.MCU.Range;
}

/******************************************************************************
** 功  能：获取平均车速
** 参  数：无
** 返回值：平均速，0.1Km/h
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Speed_Avg(void)
{
    return gxBikeInfo.MCU.Speed_Avg;
}

/******************************************************************************
** 功  能：获取最高车速
** 参  数：无
** 返回值：平均速，0.1Km/h
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Speed_Max(void)
{
    return gxBikeInfo.MCU.Speed_Max;
}

/******************************************************************************
** 功  能：获取骑行时间
** 参  数：无
** 返回值：骑行时间，单位：min
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Riding_Time(void)
{
    return gxBikeInfo.MCU.Riding_Time;
}

/******************************************************************************
** 功  能：获取电机功率
** 参  数：无
** 返回值：电机功率，单位：0.1W
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Motor_Power(void)
{
    return gxBikeInfo.MCU.Motor_Power;
}

/******************************************************************************
** 功  能：获取助推状态
** 参  数：无
** 返回值：助推状态。0-未启动，1-准备就绪，2-助推中
** 备  注：该函数在TUV模式时用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Push_Status(void)
{
    return gxBikeInfo.MCU.Push;
}

/******************************************************************************
** 功  能：获取档位
** 参  数：无
** 返回值：档位数值，0-15
** 备  注：该函数在TUV模式时，用于获取控制器发送的档位
******************************************************************************/
uint8_t ucPROTOCOL_Get_Pas(void)
{
    return gxBikeInfo.MCU.Pas;
}

/******************************************************************************
** 功  能：获取是否进入设置
** 参  数：无
** 返回值：0-未进入设置，1-进入设置
** 备  注：该函数在TUV模式时使用，用于判断是否进入设置
******************************************************************************/
uint8_t ucPROTOCOL_Get_IsInSetting(void)
{
    return gxBikeInfo.MCU.InSetting;
}

/******************************************************************************
** 功  能：获取前大灯状态
** 参  数：无
** 返回值：0-未开灯，1-开灯
** 备  注：该函数在TUV模式时使用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Lamp_Status(void)
{
    return gxBikeInfo.MCU.Head_Lamp;
}

/******************************************************************************
** 功  能：获取仪表当前要显示的骑行数据（车速、平均车速、最高车速、Trip、ODO、Time等）
** 参  数：无
** 返回值：组合值，bit0-bit1：0-单次里程，1-总里程，2-单次骑行时间，3-剩余里程
**               bit2-bit3:0-当前车速，1-平均车速，2-最高车速
** 备  注：该函数在TUV模式时使用
******************************************************************************/
uint8_t ucPROTOCOL_Get_DisplayRidingInfo(void)
{
    return gxBikeInfo.MCU.Display_RidingInfo;
}

/******************************************************************************
** 功  能：获取控制器发送过来的上键状态
** 参  数：无
** 返回值：0-未按下，1-按下
** 备  注：该函数在TUV模式时使用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Up_Key(void)
{
    return (gxBikeInfo.MCU.Button >> 3) & 0x01;
}

/******************************************************************************
** 功  能：获取控制器发送过来的下键状态
** 参  数：无
** 返回值：0-未按下，1-按下
** 备  注：该函数在TUV模式时使用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Down_Key(void)
{
    return (gxBikeInfo.MCU.Button >> 2) & 0x01;
}

/******************************************************************************
** 功  能：获取控制器发送过来的电源键状态
** 参  数：无
** 返回值：0-未按下，1-按下
** 备  注：该函数在TUV模式时使用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Power_Key(void)
{
    return (gxBikeInfo.MCU.Button >> 1) & 0x01;
}

/******************************************************************************
** 功  能：获取控制器发送过来的推行键状态
** 参  数：无
** 返回值：0-未按下，1-按下
** 备  注：该函数在TUV模式时使用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Push_Key(void)
{
    return gxBikeInfo.MCU.Button & 0x01;
}

/******************************************************************************
** 功  能：获取控制器硬件版本号1指针
** 参  数：无
** 返回值：指向硬件版本号1的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_MCU_Hard_Version_1(void)
{
    return (char *)&gxBikeInfo.MCU.Hard_Version_1;
}

/******************************************************************************
** 功  能：获取控制器硬件版本号2指针
** 参  数：无
** 返回值：指向硬件版本号2的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_MCU_Hard_Version_2(void)
{
    return (char *)&gxBikeInfo.MCU.Hard_Version_2;
}

/******************************************************************************
** 功  能：获取控制器软件版本号1指针
** 参  数：无
** 返回值：指向软件版本号1的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_MCU_Soft_Version_1(void)
{
    return (char *)&gxBikeInfo.MCU.Soft_Version_1;
}

/******************************************************************************
** 功  能：获取控制器软件版本号2指针
** 参  数：无
** 返回值：指向软件版本号2的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_MCU_Soft_Version_2(void)
{
    return (char *)&gxBikeInfo.MCU.Soft_Version_2;
}

/******************************************************************************
** 功  能：获取控制器序列号1指针
** 参  数：无
** 返回值：指向软件版本号1的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_MCU_SN_1(void)
{
    return (char *)&gxBikeInfo.MCU.SN_1;
}

/******************************************************************************
** 功  能：获取控制器序列号2指针
** 参  数：无
** 返回值：指向序列号2的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_MCU_SN_2(void)
{
    return (char *)&gxBikeInfo.MCU.SN_2;
}

/******************************************************************************
** 功  能：获取控制器序列号3指针
** 参  数：无
** 返回值：指向序列号3的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_MCU_SN_3(void)
{
    return (char *)&gxBikeInfo.MCU.SN_3;
}

/******************************************************************************
** 功  能：获取控制器参数版本号1指针
** 参  数：无
** 返回值：指向参数版本号1的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_MCU_Param_1(void)
{
    return (char *)&gxBikeInfo.MCU.Parameter_1;
}

/******************************************************************************
** 功  能：获取控制器参数版本号2指针
** 参  数：无
** 返回值：指向参数版本号2的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_MCU_Param_2(void)
{
    return (char *)&gxBikeInfo.MCU.Parameter_2;
}

/******************************************************************************
** 功  能：获取控制器参数版本号3指针
** 参  数：无
** 返回值：指向参数版本号3的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_MCU_Param_3(void)
{
    return (char *)&gxBikeInfo.MCU.Parameter_3;
}


/******************************************************************************
** 功  能：获取控制器用户ID号1指针
** 参  数：无
** 返回值：指向用户ID号1的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_MCU_UserID_1(void)
{
    return (char *)&gxBikeInfo.MCU.User_ID_1;
}

/******************************************************************************
** 功  能：获取控制器用户ID号2指针
** 参  数：无
** 返回值：指向用户ID号2的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_MCU_UserID_2(void)
{
    return (char *)&gxBikeInfo.MCU.User_ID_2;
}

/******************************************************************************
** 功  能：获取控制器数字形式的硬件版本号
** 参  数：无
** 返回值：控制器硬件版本号，0-65535
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_MCU_HardVersion_Num(void)
{
    return gxBikeInfo.MCU.Hard_Version_Num;
}

/******************************************************************************
** 功  能：获取控制器数字形式的软件版本号
** 参  数：无
** 返回值：控制器软件版本号，0-65535
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_MCU_SoftVersion_Num(void)
{
    return gxBikeInfo.MCU.Soft_Version_Num;
}

/******************************************************************************
** 功  能：获取BMS电压
** 参  数：无
** 返回值：BMS电压值，0.1V
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_BMS_Voltage(void)
{
    return gxBikeInfo.Battery.Voltage;
}

/******************************************************************************
** 功  能：获取BMS电流
** 参  数：无
** 返回值：BMS电流值，0.1V
** 备  注：
******************************************************************************/
int16_t sPROTOCOL_Get_BMS_Current(void)
{
    return (int32_t)gxBikeInfo.Battery.Current - 32768;
}

/******************************************************************************
** 功  能：获取BMS的SOH
** 参  数：无
** 返回值：SOH，1%精度
** 备  注：
******************************************************************************/
uint8_t ucPROTOCOL_Get_BMS_SOH(void)
{
    return gxBikeInfo.Battery.SOH;
}

/******************************************************************************
** 功  能：获取BMS的SOC
** 参  数：无
** 返回值：SOC，1%精度
** 备  注：
******************************************************************************/
int8_t cPROTOCOL_Get_BMS_SOC(void)
{
    return gxBikeInfo.Battery.SOC;
}

/******************************************************************************
** 功  能：获取BMS的剩余容量
** 参  数：无
** 返回值：剩余容量值，0.01Ah
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_BMS_ResCap(void)
{
    return gxBikeInfo.Battery.Capacity_Remain;
}

/******************************************************************************
** 功  能：获取BMS的循环次数
** 参  数：无
** 返回值：循环次数
** 备  注：
******************************************************************************/
uint8_t ucPROTOCOL_Get_BMS_CycleTimes(void)
{
    return gxBikeInfo.Battery.Cycle_Times;
}

/******************************************************************************
** 功  能：获取电池组串数
** 参  数：无
** 返回值：电池组串联数量
** 备  注：
******************************************************************************/
uint8_t ucPROTOCOL_Get_BMS_SeriesNum(void)
{
    return gxBikeInfo.Battery.Cell_Num_Serial;
}

/******************************************************************************
** 功  能：获取电池组并数
** 参  数：无
** 返回值：电池组并联数量
** 备  注：
******************************************************************************/
uint8_t ucPROTOCOL_Get_BMS_ParallelNum(void)
{
    return gxBikeInfo.Battery.Cell_Num_Parallel;
}


/******************************************************************************
** 功  能：获取对应电芯的电压值
** 参  数：CellNum-电芯序号，从1开始，0-14
** 返回值：电芯电压，mv
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_BMS_Cell_Voltage(uint8_t CellNum)
{
    if(CellNum > 14)
    {
        CellNum = 14;
    }
    return gxBikeInfo.Battery.Cell_Volt[CellNum];
}

/******************************************************************************
** 功  能：获取BMS条码号
** 参  数：无
** 返回值：指向BMS条码号的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_BMS_Barcode(void)
{
    return (char *)&gxBikeInfo.Battery.ID;
}

/******************************************************************************
** 功  能：获取BMS软件版本号
** 参  数：无
** 返回值：指向BMS软件版本号的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_BMS_Soft_Version(void)
{
    return (char *)&gxBikeInfo.Battery.Soft_Version_1;
}

/******************************************************************************
** 功  能：获取BMS硬件版本号1
** 参  数：无
** 返回值：指向BMS硬件版本号1的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_BMS_Hard_Version_1(void)
{
    return (char *)&gxBikeInfo.Battery.Hard_Version_1;
}

/******************************************************************************
** 功  能：获取BMS硬件版本号2
** 参  数：无
** 返回值：指向BMS硬件版本号2的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_BMS_Hard_Version_2(void)
{
    return (char *)&gxBikeInfo.Battery.Hard_Version_2;
}

/******************************************************************************
** 功  能：工厂指令的解析
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Factory_Command(can_rx_message_type *pCanRxMsg)
{
    uint16_t lusResponse;

    switch(pCanRxMsg->extended_id)
    {
    case 0x1F18016E:/*校准光感，返回0x03F8016E*/
    {
        lusResponse = vPhotoDiode_Calibration();
        vPROTOCOL_Factory_Response(pCanRxMsg->extended_id,lusResponse);
        break;
    }
    case 0x1F18025D:/*校准电压，返回0x03F8025D*/
    {
        lusResponse = vVoltage_Calibration();
        vPROTOCOL_Factory_Response(pCanRxMsg->extended_id,lusResponse);
        break;
    }
    case 0x1F180371:/*校准时间，返回0x03F80371*/
    {
        vDateTime_Calibration(pCanRxMsg->data[3],pCanRxMsg->data[4],pCanRxMsg->data[5],pCanRxMsg->data[0],pCanRxMsg->data[1],pCanRxMsg->data[2]);
        lusResponse = 1234;
        vPROTOCOL_Factory_Response(pCanRxMsg->extended_id,lusResponse);
        break;
    }
    case 0x1F18048E:/*清ODO，返回0x03F8048E*/
    {
        vClear_ODO();
        lusResponse = 5678;
        vPROTOCOL_Factory_Response(pCanRxMsg->extended_id,lusResponse);
        break;
    }
    }
}

/******************************************************************************
** 功  能：工厂指令的返回
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
static void vPROTOCOL_Factory_Response(uint32_t Cmd,uint16_t Data)
{
    can_tx_message_type    lxCanTxMessage;

    lxCanTxMessage.id_type      = CAN_ID_EXTENDED;      /*扩展帧*/
    lxCanTxMessage.frame_type   = CAN_TFT_DATA;         /*数据帧*/
    lxCanTxMessage.dlc          = 2;                    /*数据长度*/
    lxCanTxMessage.extended_id  = 0x03F80000 | (Cmd & 0x0000FFFF);
    lxCanTxMessage.data[0]      = Data >> 8;
    lxCanTxMessage.data[1]      = (uint8_t)Data;

    /*调用发送函数进行发送*/
    can_message_transmit(CAN1,&lxCanTxMessage);
}

/******************************************************************************
** 功  能：复位通信超时计数变量
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_ResetCommunicationOverTime(void)
{
    gulCommunicationCnt = 0;        /*复位通信超时计数*/
    if(gxBikeInfo.ErrCode == 0x30)
    {
        gxBikeInfo.ErrCode = 0;
    }
}


/******************************************************************************
** 功  能：开机上电时，设置默认要发送给控制器的数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Value_When_PowerOn(void)
{
    vPROTOCOL_Set_Power(1);
    vPROTOCOL_Set_Pas_Range(gtParam.Pas_Max);
    vPROTOCOL_Set_Pas(0);                                           /*开机LOGO界面发0档*/
    /*安乃达CAN协议，V3.15版本以上才支持修改轮径和限速*/
    vPROTOCOL_Set_Wheel(usGet_Wheel_Size(gtParam.Wheel_Diameter));
    vPROTOCOL_Set_LimitSpeed(gtParam.Speed_Limit * 10);             /*发送当前的限速值*/
}

/******************************************************************************
** 功  能：退出设置时，设置默认要发送给控制器的数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Value_When_ExitSetting(void)
{
    vPROTOCOL_Set_InSetting(0);                                     /*发送退出设置*/
    /*安乃达CAN协议，V3.15版本以上才支持修改轮径和限速*/
    vPROTOCOL_Set_Wheel(usGet_Wheel_Size(gtParam.Wheel_Diameter));
    vPROTOCOL_Set_LimitSpeed(gtParam.Speed_Limit * 10);             /*发送当前的限速值*/
}


